package sy3;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class Calculator extends JFrame implements ActionListener {
    private JTextField formulaDisplay;
    private JTextField resultDisplay;
    private StringBuilder input = new StringBuilder("0");
    private StringBuilder formula = new StringBuilder();
    private List<String> tokens = new ArrayList<>(); // 存储运算token（数字、运算符）
    private double memory = 0;
    private boolean isNewNumber = true;
    private boolean hasDecimal = false;
    private DecimalFormat df = new DecimalFormat("#,##0.##########");

    public Calculator() {
        setTitle("计算器");
        setSize(360, 520);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new BorderLayout(5, 5));
        setResizable(false);
        getContentPane().setBackground(Color.LIGHT_GRAY);

        // 双显示区域
        JPanel displayPanel = new JPanel(new BorderLayout());
        displayPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 0, 10));
        displayPanel.setBackground(Color.LIGHT_GRAY);

        formulaDisplay = new JTextField();
        formulaDisplay.setEditable(false);
        formulaDisplay.setHorizontalAlignment(JTextField.RIGHT);
        formulaDisplay.setFont(new Font("Segoe UI", Font.PLAIN, 16));
        formulaDisplay.setBackground(Color.WHITE);
        formulaDisplay.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        formulaDisplay.setPreferredSize(new Dimension(0, 30));
        displayPanel.add(formulaDisplay, BorderLayout.NORTH);

        resultDisplay = new JTextField("0");
        resultDisplay.setEditable(false);
        resultDisplay.setHorizontalAlignment(JTextField.RIGHT);
        resultDisplay.setFont(new Font("Segoe UI", Font.BOLD, 36));
        resultDisplay.setBackground(Color.WHITE);
        resultDisplay.setBorder(BorderFactory.createEmptyBorder(5, 5, 10, 5));
        resultDisplay.setPreferredSize(new Dimension(0, 60));
        displayPanel.add(resultDisplay, BorderLayout.CENTER);

        add(displayPanel, BorderLayout.NORTH);

        // 按钮面板
        JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(7, 4, 6, 6));
        panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        panel.setBackground(Color.LIGHT_GRAY);

        String[] btnTexts = {
                "MC", "MR", "M+", "M-",
                "%", "CE", "C", "←",
                "1/x", "x²", "√x", "÷",
                "7", "8", "9", "×",
                "4", "5", "6", "-",
                "1", "2", "3", "+",
                "+/-", "0", ".", "="
        };

        for (String text : btnTexts) {
            JButton btn = new JButton(text);
            btn.setFont(new Font("Segoe UI", Font.PLAIN, 18));
            btn.addActionListener(this);
            // 样式分组
            if (text.matches("[MC|MR|M\\+|M-]")) {
                btn.setBackground(new Color(230, 230, 230));
            } else if (text.matches("[%|CE|C|←|1/x|x²|√x|\\+/-]")) {
                btn.setBackground(new Color(240, 240, 240));
            } else if (text.matches("[\\+|×|÷|-|=]")) {
                btn.setBackground(new Color(255, 180, 70));
                btn.setForeground(Color.WHITE);
            } else {
                btn.setBackground(Color.WHITE);
            }
            btn.setFocusPainted(false);
            btn.setBorder(BorderFactory.createLineBorder(new Color(200, 200, 200)));
            panel.add(btn);
        }

        add(panel, BorderLayout.CENTER);
        setLocationRelativeTo(null);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        String cmd = e.getActionCommand();

        // 数字处理
        if (cmd.matches("[0-9]")) {
            if (isNewNumber) {
                input.setLength(0);
                hasDecimal = false;
                isNewNumber = false;
            }
            if (!(input.toString().equals("0") && cmd.equals("0"))) {
                input.append(cmd);
            }
            resultDisplay.setText(formatNumber(input.toString()));
        }
        // 小数点处理
        else if (cmd.equals(".")) {
            if (isNewNumber) {
                input.setLength(0);
                input.append("0.");
                hasDecimal = true;
                isNewNumber = false;
            } else if (!hasDecimal) {
                input.append(".");
                hasDecimal = true;
            }
            resultDisplay.setText(input.toString());
        }
        // 运算符处理（含优先级）
        else if (cmd.matches("[+×÷-]")) {
            if (!isNewNumber) {
                tokens.add(input.toString());
                tokens.add(cmd);
                formula.append(formatNumber(input.toString())).append(" ").append(cmd).append(" ");
                formulaDisplay.setText(formula.toString());
                isNewNumber = true;
                hasDecimal = false;
            }
        }
        // 等号处理（解析表达式，遵循先乘除后加减）
        else if (cmd.equals("=")) {
            if (!isNewNumber) {
                tokens.add(input.toString());
                formula.append(formatNumber(input.toString())).append(" =");
                formulaDisplay.setText(formula.toString());

                // 转换为后缀表达式（逆波兰式）
                List<String> postfix = infixToPostfix(tokens);
                // 计算后缀表达式结果
                double result = evaluatePostfix(postfix);
                updateResultDisplay(result);

                tokens.clear();
                formula.setLength(0);
                isNewNumber = true;
                hasDecimal = input.toString().contains(".");
            }
        }
        // 清除所有（C）
        else if (cmd.equals("C")) {
            resetCalculator();
            resultDisplay.setText("0");
            formulaDisplay.setText("");
        }
        // 清除输入（CE）
        else if (cmd.equals("CE")) {
            input = new StringBuilder("0");
            hasDecimal = false;
            isNewNumber = true;
            resultDisplay.setText("0");
        }
        // 退格处理
        else if (cmd.equals("←")) {
            if (input.length() > 1) {
                char last = input.charAt(input.length() - 1);
                input.deleteCharAt(input.length() - 1);
                if (last == '.') hasDecimal = false;
                resultDisplay.setText(formatNumber(input.toString()));
            } else {
                input = new StringBuilder("0");
                hasDecimal = false;
                isNewNumber = true;
                resultDisplay.setText("0");
            }
        }
        // 一元运算
        else if (cmd.equals("1/x")) {
            calculateUnaryOp(num -> {
                if (num == 0) throw new ArithmeticException("除数不能为0");
                return 1 / num;
            }, "1/(" + input + ")");
        } else if (cmd.equals("x²")) {
            calculateUnaryOp(num -> num * num, "(" + input + ")²");
        } else if (cmd.equals("√x")) {
            calculateUnaryOp(num -> {
                if (num < 0) throw new ArithmeticException("不能对负数开平方");
                return Math.sqrt(num);
            }, "√(" + input + ")");
        } else if (cmd.equals("%")) {
            calculateUnaryOp(num -> num / 100, input + "%");
        }
        // 正负号
        else if (cmd.equals("+/-")) {
            if (!input.toString().equals("0") && !isNewNumber) {
                if (input.charAt(0) == '-') {
                    input.deleteCharAt(0);
                } else {
                    input.insert(0, '-');
                }
                resultDisplay.setText(input.toString());
            }
        }
        // 内存操作
        else if (cmd.equals("MC")) {
            memory = 0;
        } else if (cmd.equals("MR")) {
            input = new StringBuilder(String.valueOf(memory));
            resultDisplay.setText(formatNumber(input.toString()));
            isNewNumber = true;
            hasDecimal = input.toString().contains(".");
        } else if (cmd.equals("M+")) {
            if (!isNewNumber) {
                memory += parseNumber(input.toString());
            }
        } else if (cmd.equals("M-")) {
            if (!isNewNumber) {
                memory -= parseNumber(input.toString());
            }
        }
    }

    // 中缀表达式转后缀表达式（逆波兰式）
    private List<String> infixToPostfix(List<String> infix) {
        List<String> postfix = new ArrayList<>();
        Stack<String> opStack = new Stack<>();
        String[] operators = {"+", "-", "×", "÷"};
        int[] precedence = {1, 1, 2, 2};

        for (String token : infix) {
            if (isNumeric(token)) {
                postfix.add(token);
            } else if (isOperator(token, operators)) {
                while (!opStack.isEmpty() && isOperator(opStack.peek(), operators) &&
                        getPrecedence(opStack.peek(), precedence) >= getPrecedence(token, precedence)) {
                    postfix.add(opStack.pop());
                }
                opStack.push(token);
            }
        }
        while (!opStack.isEmpty()) {
            postfix.add(opStack.pop());
        }
        return postfix;
    }

    // 计算后缀表达式结果
    private double evaluatePostfix(List<String> postfix) {
        Stack<Double> stack = new Stack<>();
        for (String token : postfix) {
            if (isNumeric(token)) {
                stack.push(Double.parseDouble(token.replace(",", "")));
            } else {
                double b = stack.pop();
                double a = stack.pop();
                switch (token) {
                    case "+": stack.push(a + b); break;
                    case "×": stack.push(a * b); break;
                    case "÷":
                        if (b == 0) throw new ArithmeticException("除数不能为0");
                        stack.push(a / b);
                        break;
                    case "-": stack.push(a - b); break;
                }
            }
        }
        return stack.pop();
    }

    // 辅助方法：判断是否为数字
    private boolean isNumeric(String str) {
        try {
            Double.parseDouble(str.replace(",", ""));
            return true;
        } catch (NumberFormatException e) {
            return false;
        }
    }

    // 辅助方法：判断是否为运算符
    private boolean isOperator(String str, String[] ops) {
        for (String op : ops) {
            if (op.equals(str)) return true;
        }
        return false;
    }

    // 辅助方法：获取运算符优先级
    private int getPrecedence(String op, int[] precedence) {
        if (op.equals("+") || op.equals("-")) return precedence[0];
        if (op.equals("×") || op.equals("÷")) return precedence[2];
        return 0;
    }

    // 辅助方法：处理一元运算
    private void calculateUnaryOp(UnaryOperator op, String formulaStr) {
        if (!isNewNumber) {
            try {
                double num = parseNumber(input.toString());
                double result = op.calculate(num);
                formula.setLength(0);
                formula.append(formulaStr).append(" =");
                formulaDisplay.setText(formula.toString());
                updateResultDisplay(result);
                isNewNumber = true;
                hasDecimal = input.toString().contains(".");
            } catch (ArithmeticException e) {
                showError(e.getMessage());
            }
        }
    }
    // 显示错误
    private void showError(String msg) {
        resultDisplay.setText("错误");
        formulaDisplay.setText(msg);
        input.setLength(0);
        tokens.clear();
        formula.setLength(0);
        isNewNumber = true;
        hasDecimal = false;
        Timer timer = new Timer(2000, e -> {
            resultDisplay.setText("0");
            formulaDisplay.setText("");
        });
        timer.setRepeats(false);
        timer.start();
    }

    // 重置计算器
    private void resetCalculator() {
        input = new StringBuilder("0");
        formula.setLength(0);
        tokens.clear();
        isNewNumber = true;
        hasDecimal = false;
    }

    // 格式化数字显示
    private String formatNumber(String numStr) {
        try {
            double num = Double.parseDouble(numStr);
            return df.format(num);
        } catch (NumberFormatException e) {
            return numStr;
        }
    }

    // 解析数字
    private double parseNumber(String numStr) {
        return Double.parseDouble(numStr.replace(",", ""));
    }

    // 更新结果显示
    private void updateResultDisplay(double value) {
        input = new StringBuilder(df.format(value));
        resultDisplay.setText(input.toString());
    }

    // 函数式接口
    @FunctionalInterface
    private interface UnaryOperator {
        double calculate(double num) throws ArithmeticException;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            Calculator calc = new Calculator();
            calc.setVisible(true);
        });
    }
}